package com.lipaluma.test.db.internal.assertions;

import static org.junit.Assert.fail;

import java.sql.ResultSet;
import java.sql.SQLException;


public abstract class Column<T> {
	protected String name;
	protected int index = 1;
	protected T expectedValue;
	protected String request;
	private String nullValue;

	protected Column(Builder<T> builder) {
		this.name = builder.name;
		this.index = builder.index;
		this.expectedValue = builder.expectedValue;
		this.request = builder.request;
		nullValue = builder.nullValue;
	}

	public String getName() {
		return name;
	}
	
	public T getExpectedValue() {
		return expectedValue;
	}

	public void verifyExpectedValueFromResultSet(ResultSet rs) throws SQLException {
		if(!isValueNull(rs))
			assertValue(rs);
	}
	
	private boolean isValueNull(ResultSet rs) throws SQLException {
		StringBuilder message = new StringBuilder();
		String value;
		if(name == null) {
			message.append(getErrorMessageOnIndexColumn());
			value = rs.getString(index);
		}
		else {
			message.append(getErrorMessageOnNamedColumn());
			value = rs.getString(name);
		}
		if(value == null) {
			if(!nullValue.equals(expectedValue)) {
				fail(message.append("Expected value "+expectedValue+" but was null ("+nullValue+")").toString());
			}
			return true;
		} 
		else
			return false;
	}

	public abstract void assertValue(ResultSet rs) throws SQLException;

	protected String getErrorMessageOnNamedColumn() {
		return "["+request+"] on column "+name+". ";
	}

	protected String getErrorMessageOnIndexColumn() {
		return "["+request+"] on column "+index+". ";
	}

	public static abstract class Builder<T> {
		private String name;
		private int index;
		protected T expectedValue;
		private String request;
		private String nullValue;
		
		public Builder(String request) {
			this.request = request;
		}

		public Builder<T> onIndex(int index) {
			this.index = index;
			return this;
		}

		public Builder<T> withName(String name) {
			this.name = name;
			return this;
		}

		public Builder<T> withNullValue(String nullValue) {
			this.nullValue = nullValue;
			return this;
		}

		public abstract Builder<T> withExpectedValue(String expected);
				
		public abstract Column<T> build();
	}


}
